package com.come4loves.game.module.card.facade.impl;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.ListIterator;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.come4loves.core.lock.ChainLock;
import com.come4loves.core.lock.LockUtils;
import com.come4loves.core.result.Result;
import com.come4loves.core.result.TResult;
import com.come4loves.core.utils.StringUtils;
import com.come4loves.game.constent.GameStatusCodeConstant;
import com.come4loves.game.dataconfig.model.CardConfig;
import com.come4loves.game.dataconfig.service.CardService;
import com.come4loves.game.dataconfig.service.PlayerDeckService;
import com.come4loves.game.dataconfig.service.SystemService;
import com.come4loves.game.dbproxy.entity.CardGroup;
import com.come4loves.game.module.battle.helper.PBConvertHelper;
import com.come4loves.game.module.card.constant.CardType;
import com.come4loves.game.module.card.dao.CardDao;
import com.come4loves.game.module.card.dao.CardGroupDao;
import com.come4loves.game.module.card.facade.CardGroupFacade;
import com.come4loves.game.module.card.model.CardGroupModel;
import com.come4loves.game.module.card.model.CardModel;
import com.come4loves.game.proto.CardProto.CardGroupOperationModel;

@Component
public class CardGroupFacadeImpl implements CardGroupFacade {

	public static Logger LOGGER = LoggerFactory.getLogger(CardGroupFacadeImpl.class);

	@Autowired
	public CardGroupDao cardGroupDao;

	@Autowired
	public CardDao cardDao;

	@Override
	public Result renameCardGroup(long actorId, int groupId, String name) {
		CardGroup cardGroup = cardGroupDao.getCardGroup(actorId);
		if (cardGroup.isContainsKeyModel(groupId) == false) {
			return Result.valueOf(GameStatusCodeConstant.CARD_GROUP_NOT_EXIST);
		}
		if (StringUtils.isBlank(name)) {
			return Result.valueOf(GameStatusCodeConstant.CARD_GROUP_NAME_ERROR);
		}
		TResult<Collection<CardGroupModel>> cardGroupList2 = this.getCardGroupList(actorId);
		Collection<CardGroupModel> cardGroupList = cardGroupList2.item;
		for (CardGroupModel cardGroupModel : cardGroupList) {
			if (name.equals(cardGroupModel.name) && cardGroupModel.groupId != groupId) {
				return Result.valueOf(GameStatusCodeConstant.CARD_GROUP_NAME_IS_EXIST);
			}
		}
		ChainLock lock = LockUtils.getLock(cardGroup);
		try {
			lock.lock();
			CardGroupModel cardGroupModel = cardGroupDao.getCardGroupModel(actorId, groupId);
			cardGroupModel.name = name;
			cardGroup.cardGroupMap.put(cardGroupModel.groupId, cardGroupModel);
			cardGroupDao.updateQueue(cardGroup);
		} catch (Exception exception) {
			LOGGER.error("{}", exception);
		} finally {
			lock.unlock();
		}
		return Result.valueOf();
	}

	@Override
	public TResult<CardGroupModel> createNewCardGroup(long actorId, byte flag, String name, List<CardModel> cards) {
		int maxGroupNum = SystemService.systemConfig.getCardGroupNumLimit();
		CardGroup cardGroup = cardGroupDao.getCardGroup(actorId);
		int currentGroupNum = cardGroup.cardGroupMap.size();
		if (currentGroupNum >= maxGroupNum) {
			return TResult.valueOf(GameStatusCodeConstant.CARD_GROUP_NUM_BEYOND_LIMIT);
		}

		int maxNum = Collections.max(cardGroup.cardGroupMap.keySet());
		CardGroupModel newCardGroupModel = CardGroupModel.valueOf(maxNum + 1, name, cards, flag, "");
		ChainLock lock = LockUtils.getLock(cardGroup);
		try {
			lock.lock();
			cardGroup.cardGroupMap.put(newCardGroupModel.groupId, newCardGroupModel);
			cardGroupDao.updateQueue(cardGroup);
		} catch (Exception exception) {
			LOGGER.error("{}", exception);
		} finally {
			lock.unlock();
		}
		return TResult.sucess(newCardGroupModel);
	}

	@Override
	public TResult<Collection<CardGroupModel>> getCardGroupList(long actorId) {
		CardGroup cardGroup = cardGroupDao.getCardGroup(actorId);
		if (cardGroup.cardGroupMap.values().isEmpty()) {
			ChainLock lock = LockUtils.getLock(cardGroup);
			try {
				lock.lock();
				cardGroup.cardGroupMap.put(1, PlayerDeckService.getDefaultGroupModel());
				cardGroupDao.updateQueue(cardGroup);
			} catch (Exception exception) {
				LOGGER.error("{}", exception);
			} finally {
				lock.unlock();
			}
		}
		return TResult.sucess(cardGroup.cardGroupMap.values());
	}

	@Override
	public Result addOrDelCard2Group(long actorId, int groupId, List<CardGroupOperationModel> deleteCards, List<CardGroupOperationModel> addCards) {
		CardGroup cardGroup = cardGroupDao.getCardGroup(actorId);
		if (cardGroup.isContainsKeyModel(groupId) == false) {
			return Result.valueOf(GameStatusCodeConstant.CARD_GROUP_NOT_EXIST);
		}
		if (deleteCards.isEmpty() && addCards.isEmpty()) {
//			return Result.valueOf(GameStatusCodeConstant.CARD_OPERATION_ERROR);
			return Result.valueOf();
		}
		ChainLock lock = LockUtils.getLock(cardGroup);
		try {
			lock.lock();
			CardGroupModel groupModel = cardGroup.getGroupModel(groupId);
			if (deleteCards.isEmpty() == false) {
				for (CardGroupOperationModel cardGroupOperationModel : deleteCards) {
					ListIterator<CardModel> listIterator = groupModel.cardList.listIterator();
					while(listIterator.hasNext()) {
						CardModel existCard = listIterator.next();
						if (existCard.type.ordinal() == cardGroupOperationModel.getType().getNumber() && existCard.cfgId == cardGroupOperationModel.getCfgId()) {
							listIterator.remove();
							if(addCards.isEmpty() == false) {
								CardGroupOperationModel paramCard = addCards.remove(0);
								CardType paramCardType = PBConvertHelper.cardTypeReverse(paramCard.getType());
								int paramCardId = paramCard.getCfgId();
								CardModel checkCard = groupModel.getCardModel(paramCardType, paramCardId);
								//卡牌组里没有该卡牌
								if (checkCard == null) {
									CardModel storeCard = cardDao.getCardModel(actorId, paramCardType, paramCardId);
									CardModel valueOf = CardModel.valueOf(paramCardId, storeCard.level, paramCardType, 1, storeCard.priority);
									listIterator.add(valueOf);
								} else {
									CardConfig config = CardService.getCardConfig(paramCardType, paramCardId);
									int cardCount = groupModel.getCardCount(paramCardType, paramCardId);
									if (cardCount >= config.getLimit()) {
										continue;
									} else {
										CardModel valueOf = CardModel.valueOf(checkCard.cfgId, checkCard.level, checkCard.type, 1, checkCard.priority);
										listIterator.add(valueOf);
									}
								}
							}
							break;
						}
					}
				}
			}
			if (groupModel.isFull() && addCards.isEmpty() == false) {
				return Result.valueOf(GameStatusCodeConstant.CARD_NUM_BEYOND_LIMIT);
			}
			if(addCards.isEmpty() == false) {
				for (CardGroupOperationModel addModel : addCards) {
					if (groupModel.isFull()) {
						break;
					}
					CardModel newModel = cardDao.getCardModel(actorId, PBConvertHelper.cardTypeReverse(addModel.getType()), addModel.getCfgId());
					groupModel.cardList.add(newModel);
				}
			}
			cardGroupDao.updateQueue(cardGroup);
		} catch (Exception exception) {
			LOGGER.error("{}" ,exception);
		} finally {
			lock.unlock();
		}
		return Result.valueOf();
	}

	@Override
	public Result deleteCardGroup(long actorId, int groupId) {
		CardGroup cardGroup = cardGroupDao.getCardGroup(actorId);
		if (cardGroup.isContainsKeyModel(groupId) == false) {
			return Result.valueOf(GameStatusCodeConstant.CARD_GROUP_NOT_EXIST);
		}
		ChainLock lock = LockUtils.getLock(cardGroup);
		try {
			lock.lock();
			cardGroup.cardGroupMap.remove(groupId);
			cardGroupDao.updateQueue(cardGroup);
		} catch (Exception exception) {
			LOGGER.error("{}", exception);
		} finally {
			lock.unlock();
		}
		return Result.valueOf();
	}
	
	@Override
	public Result isCardGroupExist(long actorId, int groupId) {
		CardGroup cardGroup = cardGroupDao.getCardGroup(actorId);
		if (cardGroup.isContainsKeyModel(groupId) == false) {
			return Result.valueOf(GameStatusCodeConstant.CARD_GROUP_NOT_EXIST);
		}
		return Result.valueOf();
	}

}
